// Disable warnings about invalid XML
#pragma warning(disable:4635)
#include <WebCore.h>
#pragma warning(default:4635)

#using <mscorlib.dll>
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Collections::ObjectModel;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Runtime::InteropServices;

#include "helper.h"
#include "WebViewListenerWrapper.h"
#include "WebViewWrapper.h"

namespace AwesomiumDotNet
{
	/// <summary>
	/// An enumeration of the three verbosity settings for the Awesomium Log.
	/// </summary>
	public enum class LogLevel
	{
		/// <summary> No log is created </summary>
		None,
		/// <summary> Logs only errors </summary>
		Normal,
		/// <summary> Logs everything </summary>
		Verbose
	};

	/// <summary>
	/// An enumeration of the two output pixel formats that WebView::render will use.
	/// </summary>
	public enum class PixelFormat
	{
		/// <summary> BGRA byte ordering [Blue, Green, Red, Alpha] </summary>
		Bgra,
		/// <summary> RGBA byte ordering [Red, Green, Blue, Alpha] </summary>
		Rgba
	};

#ifndef VERSION_108
	public ref class WebCoreOptions
	{
	public:
		/// <summary>
		/// An absolute path to the directory that will be used to store the cache.
		/// If an empty string is specified, the cache will not persist between sessions.
		/// </summary>
		property String^ CachePath;

		/// <summary>
		/// An absolute path to the directory that will be used to store cookies.
		/// If an empty string is specified, cookies will not persist between sessions.
		/// </summary>
		property String^ CookiePath;

		/// <summary>
		/// An absolute path that will be included in the search for plugins. This is useful
		/// if you wish to bundle certain plugins with your application.
		/// </summary>
		property String^ PluginPath;

		/// <summary>
		/// The path to store the awesomium.log. If none is specified,
		/// the log will be stored in the working directory.
		/// </summary>
		property String^ LogPath;

		/// <summary>
		/// The logging level to use (default is LogLevel.Normal).
		/// </summary>
		property LogLevel LogLevel;

		/// <summary>
		/// Whether or not to enable embedded plugins. (default is FALSE)
		/// </summary>
		property bool EnablePlugins;

		/// <summary>
		/// The pixel-format/byte-ordering to use when rendering WebViews.
		/// </summary>
		property PixelFormat PixelFormat;

		/// <summary>
		/// The user agent string that will override the default.
		/// Leave empty to use the default user agent.
		/// </summary>
		property String^ UserAgentOverride;

		WebCoreOptions()
		{
			LogLevel = AwesomiumDotNet::LogLevel::Normal;
		}
	};
#endif


	/// <summary>
	/// The WebCore manages the creation of WebViews, the internal worker thread,
	/// and various other global states that are required to embed Chromium.
	/// </summary>
	public ref class WebCore : IDisposable
	{
	private:
		Awesomium::WebCore* webCore;

	public:
		/// <summary>
		/// Instantiates the WebCore.
		/// </summary>
		WebCore()
		{
			webCore = new Awesomium::WebCore();
		}

#ifdef VERSION_108
		/// <summary>
		/// Instantiates the WebCore.
		/// </summary>
		/// <param name="level">
		/// The logging level to use (default is LogLevel.Normal).
		/// </param>
		WebCore(LogLevel level)
		{
			webCore = new Awesomium::WebCore((Awesomium::LogLevel)level);
		}

		/// <summary>
		/// Instantiates the WebCore.
		/// </summary>
		/// <param name="level">
		/// The logging level to use (default is LogLevel.Normal).
		/// </param>
		/// <param name="enablePlugins">
		/// Whether or not to enable embedded plugins.
		/// </param>
		WebCore(LogLevel level, bool enablePlugins)
		{
			webCore = new Awesomium::WebCore((Awesomium::LogLevel)level, enablePlugins);
		}

		/// <summary>
		/// Instantiates the WebCore.
		/// </summary>
		/// <param name="level">
		/// The logging level to use (default is LogLevel.Normal).
		/// </param>
		/// <param name="enablePlugins">
		/// Whether or not to enable embedded plugins.
		/// </param>
		/// <param name="pixelFormat">
		/// The pixel-format/byte-ordering to use when rendering WebViews.
		/// </param>
		WebCore(LogLevel level, bool enablePlugins, PixelFormat pixelFormat)
		{
			webCore = new Awesomium::WebCore((Awesomium::LogLevel)level,
				enablePlugins, (Awesomium::PixelFormat)pixelFormat);
		}
#else
		/// <summary>
		/// Instantiates the WebCore.
		/// </summary>
		WebCore(WebCoreOptions^ options)
		{
			std::wstring cachePathString;
			std::wstring cookiePathString;
			std::wstring pluginPathString;
			std::wstring logPathString;
			std::string userAgentOverrideString;

			if (options->CachePath != nullptr)
				MarshalString(options->CachePath, cachePathString);
			else
				cachePathString = L"";

			if (options->CookiePath != nullptr)
				MarshalString(options->CookiePath, cookiePathString);
			else
				cachePathString = L"";

			if (options->PluginPath != nullptr)
				MarshalString(options->PluginPath, pluginPathString);
			else
				pluginPathString = L"";

			if (options->LogPath != nullptr)
				MarshalString(options->LogPath, logPathString);
			else
				logPathString = L"";

			if (options->UserAgentOverride != nullptr)
				MarshalString(options->UserAgentOverride, userAgentOverrideString);
			else
				userAgentOverrideString = "";

			webCore = new Awesomium::WebCore(cachePathString, cookiePathString,
				pluginPathString, logPathString, (Awesomium::LogLevel)options->LogLevel,
				options->EnablePlugins, (Awesomium::PixelFormat)options->PixelFormat, userAgentOverrideString
				);
		}
#endif

		/// <summary>
		/// Destroys the WebCore singleton. (Also destroys any lingering WebViews)
		/// </summary>
		virtual ~WebCore()
		{
			delete webCore;
			webCore = 0;
		}

		/// <summary>
		/// Creates a new WebView.
		/// </summary>
		/// <param name="width">
		/// The width of the WebView in pixels.
		/// </param>
		/// <param name="height">
		/// The height of the WebView in pixels.
		/// </param>
		/// <returns>
		/// Returns a WebView Instance.
		/// </returns>
		WebView^ CreateWebView(int width, int height)
		{
			return gcnew WebView(webCore, width, height);
		}

		/// <summary>
		/// Creates a new WebView.
		/// </summary>
		/// <param name="width">
		/// The width of the WebView in pixels.
		/// </param>
		/// <param name="height">
		/// The height of the WebView in pixels.
		/// </param>
		/// <param name="isTransparent">
		/// Whether or not the background of a WebView should be rendered as transparent.
		/// </param>
		/// <returns>
		/// Returns a WebView Instance.
		/// </returns>
		WebView^ CreateWebView(int width, int height, bool isTransparent)
		{
			return gcnew WebView(webCore, width, height, isTransparent);
		}

		/// <summary>
		/// Creates a new WebView.
		/// </summary>
		/// <param name="width">
		/// The width of the WebView in pixels.
		/// </param>
		/// <param name="height">
		/// The height of the WebView in pixels.
		/// </param>
		/// <param name="isTransparent">
		/// Whether or not the background of a WebView should be rendered as transparent.
		/// </param>
		/// <param name="enableAsyncRendering">
		/// Enables fully-asynchronous rendering, see remarks.
		/// </param>
		/// <returns>
		/// Returns a WebView Instance.
		/// </returns>
		/// <remark>
		/// When asynchronous rendering is enabled, all rendering takes place on
		/// another thread asynchronously. The benefit of this behavior is that you
		/// may see a marked performance increase on machines with multi-core
		/// processors (especially when a WebView has high-animation content).
		/// </remark>
		WebView^ CreateWebView(int width, int height, bool isTransparent, bool enableAsyncRendering)
		{
			return gcnew WebView(webCore, width, height, isTransparent, enableAsyncRendering);
		}

		/// <summary>
		/// Creates a new WebView.
		/// </summary>
		/// <param name="width">
		/// The width of the WebView in pixels.
		/// </param>
		/// <param name="height">
		/// The height of the WebView in pixels.
		/// </param>
		/// <param name="isTransparent">
		/// Whether or not the background of a WebView should be rendered as transparent.
		/// </param>
		/// <param name="enableAsyncRendering">
		/// Enables fully-asynchronous rendering, see remarks.
		/// </param>
		/// <param name="maxAsyncRenderPerSec">
		/// The maximum times per second this WebView should asynchronously render.
		/// </param>
		/// <returns>
		/// Returns a WebView Instance.
		/// </returns>
		/// <remark>
		/// When asynchronous rendering is enabled, all rendering takes place on
		/// another thread asynchronously. The benefit of this behavior is that you
		/// may see a marked performance increase on machines with multi-core
		/// processors (especially when a WebView has high-animation content).
		/// </remark>
		WebView^ CreateWebView(int width, int height, bool isTransparent, bool enableAsyncRendering, int maxAsyncRenderPerSec)
		{
			return gcnew WebView(webCore, width, height, isTransparent, enableAsyncRendering, maxAsyncRenderPerSec);
		}

		/// <summary>
		/// The current base directory.
		/// </summary>
		property String^ BaseDirectory
		{
			String^ get()
			{
				return gcnew String(webCore->getBaseDirectory().c_str());
			}
			void set(String^ value)
			{
				#ifdef VERSION_108
				std::string valueString;
				#else
				std::wstring valueString;
				#endif
				MarshalString(value, valueString);
				webCore->setBaseDirectory(valueString);
			}
		}

		/// <summary>
		/// The pixel format being used.
		/// </summary>
		property AwesomiumDotNet::PixelFormat PixelFormat
		{
			AwesomiumDotNet::PixelFormat get()
			{
				return (AwesomiumDotNet::PixelFormat)webCore->getPixelFormat();
			}
		}

		/// <summary>
		/// Sets a custom response page to use when a WebView encounters a certain
		/// HTML status code from the server (such as '404 - File not found').
		/// </summary>
		/// <param name="statusCode">
		/// The status code this response page should be associated with.
		/// See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
		/// </param>
		/// <param name="filePath">
		/// The local page to load as a response, should be a path relative to the base directory.
		/// </param>
		void SetCustomResponsePage(int statusCode, String^ filePath)
		{
			std::string filePathString;
			MarshalString(filePath, filePathString);
			webCore->setCustomResponsePage(statusCode, filePathString);
		}

		/// <summary>
		/// Whether or not plugins are enabled.
		/// </summary>
		property bool ArePluginsEnabled
		{
			bool get() { return webCore->arePluginsEnabled(); }
		}

		/// <summary>
		/// Updates the WebCore and allows it to conduct various operations such as the propagation
		/// of bound JS callbacks and the invocation of any queued listener events.
		/// </summary>
		void Update()
		{
			webCore->update();
		}

		/// <summary>
		/// Pauses the internal thread of the Awesomium WebCore.
		/// </summary>
		/// <remarks>
		/// The pause and resume functions were added as a temporary workaround
		/// for threading issues with Flash plugins on the Mac OSX platform.
		/// You should call WebCore::pause right before handling the message loop
		/// in your main thread (usually via SDL_PollEvents) and immediately call
		/// resume after.
		/// </remarks>
		void Pause()
		{
			webCore->pause();
		}

		/// <summary>
		/// Resumes the internal thread of the Awesomium WebCore.
		/// </summary>
		/// <seealso cref="Pause"/>
		void Resume()
		{
			webCore->resume();
		}
	};
}
